/*
 * 
* Copyright (C) 2004-2006  Autodesk, Inc.
* 
* This library is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser
* General Public License as published by the Free Software Foundation.
* 
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
* 
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
* 
 */

#include "Pch.h"
#include "UpdateTests.h"
#include "UnitTestUtility.h"

#include <FdoSpatial.h>
#include <FdoCommonFile.h>

#ifdef _WIN32
#define LOCATION L"..\\..\\TestData\\Testing"
#else
#define LOCATION L"../../TestData/Testing"
#endif

CPPUNIT_TEST_SUITE_REGISTRATION (UpdateTests);
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION (UpdateTests, "UpdateTests");

FdoPtr<FdoIConnection> UpdateTests::mConnection;

static std::wstring strSchema[2] = {L"TAB", L"MIF"};

UpdateTests::UpdateTests (void)
{
}

UpdateTests::~UpdateTests (void)
{
}

void UpdateTests::setUp ()
{
    if (!FdoCommonFile::FileExists (LOCATION))
        FdoCommonFile::MkDir (LOCATION);
    mConnection = MapInfoTests::GetConnection ();
    mConnection->SetConnectionString (L"DefaultFileLocation=" LOCATION);
    CPPUNIT_ASSERT_MESSAGE ("connection state not open", FdoConnectionState_Open == mConnection->Open ());
}

void UpdateTests::tearDown ()
{
    // delete the class, if its there:
    for (size_t i = 0; i < strSchema->size(); ++i)
        TestCommonSchemaUtil::CleanUpClass(mConnection, strSchema[i].c_str(), L"Test");

    mConnection->Close ();
    FDO_SAFE_RELEASE(mConnection.p);

    if (FdoCommonFile::FileExists (LOCATION))
        FdoCommonFile::RmDir (LOCATION);
}

void UpdateTests::create_schema (FdoGeometricType type, bool elevation, bool measure)
{
    // delete the class, if its there:
    TestCommonSchemaUtil::CleanUpClass(mConnection, NULL, L"Test");

    for(int i = 0; i < 2; i++)
    {
        // Describe schemas
        FdoPtr<FdoIDescribeSchema> cmdDescSchema = (FdoIDescribeSchema*)mConnection->CreateCommand(FdoCommandType_DescribeSchema);
        FdoPtr<FdoFeatureSchemaCollection> schemas = cmdDescSchema->Execute();


        // create the class
        FdoPtr<FdoFeatureSchema> schema = schemas->GetItem(strSchema[i].c_str());
        FdoPtr<FdoClassCollection> classes = schema->GetClasses ();

        FdoPtr<FdoDataPropertyDefinition> featid = FdoDataPropertyDefinition::Create (L"FeatId", L"integer");
        featid->SetDataType (FdoDataType_Int32);
        featid->SetIsAutoGenerated (true);
        featid->SetNullable (false);

        FdoPtr<FdoDataPropertyDefinition> id = FdoDataPropertyDefinition::Create (L"Id", L"integer");
        id->SetDataType (FdoDataType_Decimal);
        id->SetPrecision(10);
        id->SetScale(0);

        FdoPtr<FdoDataPropertyDefinition> street = FdoDataPropertyDefinition::Create (L"Street", L"text");
        street->SetDataType (FdoDataType_String);
        street->SetLength (64);

        FdoPtr<FdoDataPropertyDefinition> area = FdoDataPropertyDefinition::Create (L"Area", L"double");
        area->SetDataType (FdoDataType_Decimal);
        area->SetPrecision (20);
        area->SetScale (7);

        FdoPtr<FdoDataPropertyDefinition> vacant = FdoDataPropertyDefinition::Create (L"Vacant", L"boolean");
        vacant->SetDataType (FdoDataType_Boolean);

        FdoPtr<FdoDataPropertyDefinition> birthday = FdoDataPropertyDefinition::Create (L"Birthday", L"date");
        birthday->SetDataType (FdoDataType_DateTime);

        FdoPtr<FdoDataPropertyDefinition> age = FdoDataPropertyDefinition::Create (L"Age", L"an int32 property");
        age->SetDataType (FdoDataType_Int32);

        // build a location geometry property
        FdoPtr<FdoGeometricPropertyDefinition> location = FdoGeometricPropertyDefinition::Create (L"Geometry", L"geometry");
        location->SetGeometryTypes (type);
        location->SetHasElevation (elevation);
        location->SetHasMeasure (measure);

        //// assemble the feature class
        FdoPtr<FdoFeatureClass> feature = FdoFeatureClass::Create (L"Test", L"test class created with apply schema");
        FdoPtr<FdoPropertyDefinitionCollection> properties = feature->GetProperties ();
        FdoPtr<FdoDataPropertyDefinitionCollection> identities = feature->GetIdentityProperties ();
        properties->Add (featid);
        identities->Add (featid);
        properties->Add (id);
        properties->Add (street);
        properties->Add (area);
        properties->Add (vacant);
        properties->Add (birthday);
        properties->Add (age);
        properties->Add (location);
        feature->SetGeometryProperty (location);

        // submit the new schema
        classes->Add (feature);
        FdoPtr<FdoIApplySchema> apply = (FdoIApplySchema*)mConnection->CreateCommand (FdoCommandType_ApplySchema);
        apply->SetFeatureSchema (schema);
        apply->Execute ();
    }
}

void UpdateTests::update ()
{
    try
    {
        create_schema (FdoGeometricType_Point, true, true);
        for(int i = 0; i < 2; i++)
        {
            FdoPtr<FdoIInsert> insert = (FdoIInsert*)mConnection->CreateCommand (FdoCommandType_Insert);
            insert->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            FdoPtr<FdoPropertyValueCollection> values = insert->GetPropertyValues ();
            FdoPtr<FdoValueExpression> expression = (FdoValueExpression*)MapInfoTests::ParseByDataType (L"24", FdoDataType_Decimal);
            FdoPtr<FdoPropertyValue> value = FdoPropertyValue::Create (L"Id", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"'1147 Trafford Drive'");
            value = FdoPropertyValue::Create (L"Street", expression);
            values->Add (value);
            // add NULL geometry value:
            FdoPtr<FdoGeometryValue> geometry = FdoGeometryValue::Create ();
            geometry->SetNullValue ();
            value = FdoPropertyValue::Create (L"Geometry", geometry);
            values->Add (value);
            FdoPtr<FdoIFeatureReader> reader = insert->Execute ();
            FdoInt32 featid;
            featid = -1;
            while (reader->ReadNext ())
            {
                if (-1 != featid)
                    CPPUNIT_FAIL ("too many features inserted");
                featid = reader->GetInt32 (L"FeatId");
            }
            reader->Close ();
            if (-1 == featid)
                CPPUNIT_FAIL ("too few features inserted");

            // update it
            FdoPtr<FdoIUpdate> update = (FdoIUpdate*)mConnection->CreateCommand (FdoCommandType_Update);
            update->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            wchar_t filter[1024];
            FdoCommonOSUtil::swprintf (filter, ELEMENTS(filter), L"%ls = %d", L"FeatId", featid);
            update->SetFilter (FdoPtr<FdoFilter>(FdoFilter::Parse (filter)));
            values = update->GetPropertyValues ();
            value = FdoPropertyValue::Create ();
            value->SetName (L"Street");
            value->SetValue (L"'88 Noodle Court'");
            values->Add (value);
            if (1 != update->Execute ())
                CPPUNIT_FAIL ("update execute failed");

            // check by doing a select
            FdoPtr<FdoISelect> select = (FdoISelect*)mConnection->CreateCommand (FdoCommandType_Select);
            select->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            reader = select->Execute ();
            while (reader->ReadNext ())
            {
                CPPUNIT_ASSERT_MESSAGE ("incorrect featid value", featid == reader->GetInt32 (L"FeatId"));
                CPPUNIT_ASSERT_MESSAGE ("incorrect id value", 24 == reader->GetDouble (L"Id"));
                CPPUNIT_ASSERT_MESSAGE ("incorrect street value", 0 == wcscmp (L"88 Noodle Court", reader->GetString (L"Street")));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect area value", reader->IsNull(L"Area"));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect vacant value", reader->IsNull(L"Vacant"));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect birthday year value", reader->IsNull (L"Birthday"));
                CPPUNIT_ASSERT_MESSAGE ("incorrect geometry value", reader->IsNull (L"Geometry"));
            }
            reader->Close ();
        }
    }
    catch (FdoException* ge) 
    {
        TestCommonFail (ge);
    }
}

void UpdateTests::update_geometry_point_xy ()
{
    try
    {
        create_schema (FdoGeometricType_Point, false, false);
        for(int i = 0; i < 2; i++)
        {
            FdoPtr<FdoIInsert> insert = (FdoIInsert*)mConnection->CreateCommand (FdoCommandType_Insert);
            insert->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            FdoPtr<FdoPropertyValueCollection> values = insert->GetPropertyValues ();
            FdoPtr<FdoValueExpression> expression = (FdoValueExpression*)MapInfoTests::ParseByDataType (L"24", FdoDataType_Decimal);
            FdoPtr<FdoPropertyValue> value = FdoPropertyValue::Create (L"Id", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"'1147 Trafford Drive'");
            value = FdoPropertyValue::Create (L"Street", expression);
            values->Add (value);
            // add real geometry value:
            FdoPtr<FdoGeometryValue> geometry = (FdoGeometryValue*)FdoExpression::Parse (L"GEOMFROMTEXT ('POINT XY ( 999000 -999000 )')");
            value = FdoPropertyValue::Create (L"Geometry", geometry);
            values->Add (value);
            FdoPtr<FdoIFeatureReader> reader = insert->Execute ();
            FdoInt32 featid;
            featid = -1;
            while (reader->ReadNext ())
            {
                if (-1 != featid)
                    CPPUNIT_FAIL ("too many features inserted");
                featid = reader->GetInt32 (L"FeatId");
            }
            reader->Close ();
            if (-1 == featid)
                CPPUNIT_FAIL ("too few features inserted");

            // update it
            FdoPtr<FdoIUpdate> update = (FdoIUpdate*)mConnection->CreateCommand (FdoCommandType_Update);
            update->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            wchar_t filter[1024];
            FdoCommonOSUtil::swprintf (filter, ELEMENTS(filter), L"%ls = %d", L"FeatId", featid);
            update->SetFilter (FdoPtr<FdoFilter>(FdoFilter::Parse (filter)));
            values = update->GetPropertyValues ();
            geometry = (FdoGeometryValue*)FdoExpression::Parse (L"GEOMFROMTEXT ('POINT XY ( 25626 2929 )')");
            value = FdoPropertyValue::Create (L"Geometry", geometry);
            value->SetName (L"Geometry");
            value->SetValue (geometry);
            values->Add (value);
            if (1 != update->Execute ())
                CPPUNIT_FAIL ("update execute failed");

            // check by doing a select
            FdoPtr<FdoISelect> select = (FdoISelect*)mConnection->CreateCommand (FdoCommandType_Select);
            select->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            reader = select->Execute ();
            while (reader->ReadNext ())
            {
                CPPUNIT_ASSERT_MESSAGE ("incorrect featid value", featid == reader->GetInt32 (L"FeatId"));
                CPPUNIT_ASSERT_MESSAGE ("incorrect id value", 24 == reader->GetDouble (L"Id"));
                CPPUNIT_ASSERT_MESSAGE ("incorrect street value", 0 == wcscmp (L"1147 Trafford Drive", reader->GetString (L"Street")));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect area value", reader->IsNull(L"Area"));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect vacant value", reader->IsNull(L"Vacant"));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect birthday year value", reader->IsNull (L"Birthday"));
                CPPUNIT_ASSERT_MESSAGE ("TAB is null", !reader->IsNull (L"Geometry"));
                FdoPtr<FdoByteArray> before = geometry->GetGeometry ();
                FdoPtr<FdoByteArray> after = reader->GetGeometry (L"Geometry");
                CPPUNIT_ASSERT_MESSAGE ("incorrect geometry size", before->GetCount () == after->GetCount ());
                int count = before->GetCount ();
                FdoPtr<FdoFgfGeometryFactory> gf = FdoFgfGeometryFactory::GetInstance();
                FdoIPoint * pGeomB = (FdoIPoint*)gf->CreateGeometryFromFgf(before->GetData(), count);
                FdoIPoint * pGeomA = (FdoIPoint*)gf->CreateGeometryFromFgf(after->GetData(), count);
                CPPUNIT_ASSERT_MESSAGE ("incorrect geometry content", UnitTestUtil::PointsEqual(pGeomB, pGeomA));
            }
            reader->Close ();
        }
    }
    catch (FdoException* ge) 
    {
        TestCommonFail (ge);
    }
}

// in this test the shape gets bigger, forcing the back end of the file to move
void UpdateTests::update_geometry_line_xy ()
{
    try
    {
        create_schema (FdoGeometricType_Curve, false, false);
        for(int i = 0; i < 2; i++)
        {
            FdoPtr<FdoIInsert> insert = (FdoIInsert*)mConnection->CreateCommand (FdoCommandType_Insert);
            insert->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            FdoPtr<FdoPropertyValueCollection> values = insert->GetPropertyValues ();
            FdoPtr<FdoValueExpression> expression = FdoDecimalValue::Create (INT_MAX);
            FdoPtr<FdoPropertyValue> value = FdoPropertyValue::Create (L"Id", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"'~!@#$%^&*()'");
            value = FdoPropertyValue::Create (L"Street", expression);
            values->Add (value);
            expression = (FdoValueExpression*)MapInfoTests::ParseByDataType (L"-8.8282e11", FdoDataType_Decimal);
            value = FdoPropertyValue::Create (L"Area", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"false");
            value = FdoPropertyValue::Create (L"Vacant", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"DATE'1957-3-2'");
            value = FdoPropertyValue::Create (L"Birthday", expression);
            values->Add (value);

            // add geometry value:
            FdoPtr<FdoGeometryValue> geometry = (FdoGeometryValue*)FdoExpression::Parse (L"GEOMFROMTEXT ('LINESTRING XY ( 7171.723 8282.99, 6824.82 6545.87, 8920.5 9929.77)')");
            value = FdoPropertyValue::Create (L"Geometry", geometry);
            values->Add (value);
            FdoPtr<FdoIFeatureReader> reader = insert->Execute ();
            FdoInt32 id;
            id = -1;
            while (reader->ReadNext ())
            {
                if (-1 != id)
                    CPPUNIT_FAIL ("too many features inserted");
                id = reader->GetInt32 (L"FeatId");
            }
            reader->Close ();

            if (-1 == id)
                CPPUNIT_FAIL ("too few features inserted");

            // insert a second one
            FdoPtr<FdoGeometryValue> geometry2 = (FdoGeometryValue*)FdoExpression::Parse (L"GEOMFROMTEXT ('LINESTRING XY ( 6677.99 7820.89, 6272.90 7020.20, 7012.82 7516.91)')");
            value->SetValue (geometry2);
            reader = insert->Execute ();
            FdoInt32 id2;
            id2 = -1;
            while (reader->ReadNext ())
            {
                if (-1 != id2)
                    CPPUNIT_FAIL ("too many features inserted");
                id2 = reader->GetInt32 (L"FeatId");
            }
            reader->Close ();

            // update the first one
            FdoPtr<FdoIUpdate> update = (FdoIUpdate*)mConnection->CreateCommand (FdoCommandType_Update);
            update->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            wchar_t filter[1024];
            FdoCommonOSUtil::swprintf (filter, ELEMENTS(filter), L"%ls = %d", L"FeatId", id);
            update->SetFilter (FdoPtr<FdoFilter>(FdoFilter::Parse (filter)));
            values = update->GetPropertyValues ();
            FdoPtr<FdoGeometryValue> geometry3 = (FdoGeometryValue*)FdoExpression::Parse (L"GEOMFROMTEXT ('LINESTRING XY ( 123.45 872.45, 891.23 828.77, 882.99 728.34, 677.92 776.43, 552.52 928.45)')");
            value = FdoPropertyValue::Create (L"Geometry", geometry3);
            value->SetName (L"Geometry");
            value->SetValue (geometry3);
            values->Add (value);
            if (1 != update->Execute ())
                CPPUNIT_FAIL ("update execute failed");

            // check by doing a select
            FdoPtr<FdoISelect> select = (FdoISelect*)mConnection->CreateCommand (FdoCommandType_Select);
            select->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            reader = select->Execute ();
            while (reader->ReadNext ())
            {
                if (id == reader->GetInt32 (L"FeatId"))
                {
                    CPPUNIT_ASSERT_MESSAGE ("incorrect id value", INT_MAX == reader->GetDouble (L"Id"));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect street value", 0 == wcscmp (L"~!@#$%^&*()", reader->GetString (L"Street")));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect area value", -8.8282e11 == reader->GetDouble (L"Area"));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect vacant value", !reader->GetBoolean (L"Vacant"));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect birthday value", 1957 == reader->GetDateTime (L"Birthday").year);
                    CPPUNIT_ASSERT_MESSAGE ("incorrect birthday value", 3 == reader->GetDateTime (L"Birthday").month);
                    CPPUNIT_ASSERT_MESSAGE ("incorrect birthday value", 2 == reader->GetDateTime (L"Birthday").day);
                    CPPUNIT_ASSERT_MESSAGE ("geometry is null", !reader->IsNull (L"Geometry"));
                    FdoPtr<FdoByteArray> before = geometry3->GetGeometry ();
                    FdoPtr<FdoByteArray> after = reader->GetGeometry (L"Geometry");
                    int b = before->GetCount ();
                    int a = after->GetCount ();
                    CPPUNIT_ASSERT_MESSAGE ("incorrect geometry size", b == a);
                    int count = before->GetCount ();
                    FdoPtr<FdoFgfGeometryFactory> gf = FdoFgfGeometryFactory::GetInstance();
                    FdoPtr<FdoIGeometry> pGeomB = gf->CreateGeometryFromFgf(before->GetData(), count);
                    FdoPtr<FdoIGeometry> pGeomA = gf->CreateGeometryFromFgf(after->GetData(), count);
                    CPPUNIT_ASSERT_MESSAGE ("incorrect geometry content", UnitTestUtil::LineEqual(pGeomB, pGeomA));
                }
                else if (id2 == reader->GetInt32 (L"FeatId"))
                {
                    CPPUNIT_ASSERT_MESSAGE ("incorrect id value", INT_MAX == reader->GetDouble (L"Id"));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect street value", 0 == wcscmp (L"~!@#$%^&*()", reader->GetString (L"Street")));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect area value", -8.8282e11 == reader->GetDouble (L"Area"));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect vacant value", !reader->GetBoolean (L"Vacant"));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect birthday value", 1957 == reader->GetDateTime (L"Birthday").year);
                    CPPUNIT_ASSERT_MESSAGE ("incorrect birthday value", 3 == reader->GetDateTime (L"Birthday").month);
                    CPPUNIT_ASSERT_MESSAGE ("incorrect birthday value", 2 == reader->GetDateTime (L"Birthday").day);
                    CPPUNIT_ASSERT_MESSAGE ("geometry is null", !reader->IsNull (L"Geometry"));
                    FdoPtr<FdoByteArray> before = geometry2->GetGeometry ();
                    FdoPtr<FdoByteArray> after = reader->GetGeometry (L"Geometry");
                    int b = before->GetCount ();
                    int a = after->GetCount ();
                    CPPUNIT_ASSERT_MESSAGE ("incorrect geometry size", b == a);
                    int count = before->GetCount ();
                    FdoPtr<FdoFgfGeometryFactory> gf = FdoFgfGeometryFactory::GetInstance();
                    FdoPtr<FdoIGeometry> pGeomB = gf->CreateGeometryFromFgf(before->GetData(), count);
                    FdoPtr<FdoIGeometry> pGeomA = gf->CreateGeometryFromFgf(after->GetData(), count);
                    CPPUNIT_ASSERT_MESSAGE ("incorrect geometry content", UnitTestUtil::LineEqual(pGeomB, pGeomA));
                }
            }
            reader->Close ();
        }
    }
    catch (FdoException* ge) 
    {
        TestCommonFail (ge);
    }
}

// in this test the shape gets smaller, forcing the back end of the file to move
void UpdateTests::update_geometry_polygon_xy ()
{
    try
    {
        create_schema (FdoGeometricType_Surface, false, false);
        for(int i = 0; i < 2; i++)
        {
            FdoPtr<FdoIInsert> insert = (FdoIInsert*)mConnection->CreateCommand (FdoCommandType_Insert);
            insert->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            FdoPtr<FdoPropertyValueCollection> values = insert->GetPropertyValues ();
            FdoPtr<FdoValueExpression> expression = (FdoValueExpression*)MapInfoTests::ParseByDataType (L"7", FdoDataType_Decimal);
            FdoPtr<FdoPropertyValue> value = FdoPropertyValue::Create (L"Id", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"'Linux Loop'");
            value = FdoPropertyValue::Create (L"Street", expression);
            values->Add (value);
            expression = FdoDecimalValue::Create (99.9999);
            value = FdoPropertyValue::Create (L"Area", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"true");
            value = FdoPropertyValue::Create (L"Vacant", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"DATE'2005-03-22'");
            value = FdoPropertyValue::Create (L"Birthday", expression);
            values->Add (value);

            // add geometry value:
            FdoPtr<FdoGeometryValue> geometry = (FdoGeometryValue*)FdoExpression::Parse (L"GeomFromText('POLYGON XY ((5108.8 5104.7, 5109.02 5104.97, 5109.13 5105.94, 5113.45 5145.13, 5109.2 5138.67, 5108.8 5104.7))')");
            value = FdoPropertyValue::Create (L"Geometry", geometry);
            values->Add (value);
            FdoPtr<FdoIFeatureReader> reader = insert->Execute ();
            FdoInt32 id;
            id = -1;
            while (reader->ReadNext ())
            {
                if (-1 != id)
                    CPPUNIT_FAIL ("too many features inserted");
                id = reader->GetInt32 (L"FeatId");
            }
            reader->Close ();
            if (-1 == id)
                CPPUNIT_FAIL ("too few features inserted");

            // insert a second one
            FdoPtr<FdoGeometryValue> geometry2 = (FdoGeometryValue*)FdoExpression::Parse (L"GEOMFROMTEXT ('POLYGON XY ((2056.56 2345.87, 2067.54 2435.78, 1923.67 2390.87, 2056.56 2345.87))')");
            value->SetValue (geometry2);
            reader = insert->Execute ();
            FdoInt32 id2;
            id2 = -1;
            while (reader->ReadNext ())
            {
                if (-1 != id2)
                    CPPUNIT_FAIL ("too many features inserted");
                id2 = reader->GetInt32 (L"FeatId");
            }
            reader->Close ();

            // update the first one
            FdoPtr<FdoIUpdate> update = (FdoIUpdate*)mConnection->CreateCommand (FdoCommandType_Update);
            update->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            wchar_t filter[1024];
            FdoCommonOSUtil::swprintf (filter, ELEMENTS(filter), L"%ls = %d", L"FeatId", id);
            update->SetFilter (FdoPtr<FdoFilter>(FdoFilter::Parse (filter)));
            values = update->GetPropertyValues ();
            FdoPtr<FdoGeometryValue> geometry3 = (FdoGeometryValue*)FdoExpression::Parse (L"GEOMFROMTEXT ('POLYGON XY ((5108.8 5104.7, 5109.02 5104.97, 5109.2 5138.67, 5108.8 5104.7))')");
            value = FdoPropertyValue::Create (L"Geometry", geometry3);
            value->SetName (L"Geometry");
            value->SetValue (geometry3);
            values->Add (value);
            if (1 != update->Execute ())
                CPPUNIT_FAIL ("update execute failed");

            // check by doing a select
            FdoPtr<FdoISelect> select = (FdoISelect*)mConnection->CreateCommand (FdoCommandType_Select);
            select->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            reader = select->Execute ();
            while (reader->ReadNext ())
            {
                if (id == reader->GetInt32 (L"FeatId"))
                {
                    CPPUNIT_ASSERT_MESSAGE ("incorrect id value", 7 == reader->GetDouble (L"Id"));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect street value", 0 == wcscmp (L"Linux Loop", reader->GetString (L"Street")));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect area value", 99.9999 == reader->GetDouble (L"Area"));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect vacant value", reader->GetBoolean (L"Vacant"));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect birthday value", 2005 == reader->GetDateTime (L"Birthday").year);
                    CPPUNIT_ASSERT_MESSAGE ("incorrect birthday value", 3 == reader->GetDateTime (L"Birthday").month);
                    CPPUNIT_ASSERT_MESSAGE ("incorrect birthday value", 22 == reader->GetDateTime (L"Birthday").day);
                    CPPUNIT_ASSERT_MESSAGE ("geometry is null", !reader->IsNull (L"Geometry"));
                    FdoPtr<FdoByteArray> before = geometry3->GetGeometry ();
                    FdoPtr<FdoByteArray> after = reader->GetGeometry (L"Geometry");
                    int b = before->GetCount ();
                    int a = after->GetCount ();
                    CPPUNIT_ASSERT_MESSAGE ("incorrect geometry size", b == a);
                    int count = before->GetCount ();
                    FdoPtr<FdoFgfGeometryFactory> gf = FdoFgfGeometryFactory::GetInstance();
                    FdoPtr<FdoIGeometry> pGeomB = gf->CreateGeometryFromFgf(before->GetData(), count);
                    FdoPtr<FdoIGeometry> pGeomA = gf->CreateGeometryFromFgf(after->GetData(), count);
                    CPPUNIT_ASSERT_MESSAGE ("incorrect geometry content", UnitTestUtil::PolygonEqual(pGeomB, pGeomA));
                }
                else if (id2 == reader->GetInt32 (L"FeatId"))
                {
                    CPPUNIT_ASSERT_MESSAGE ("incorrect id value", 7 == reader->GetDouble (L"Id"));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect street value", 0 == wcscmp (L"Linux Loop", reader->GetString (L"Street")));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect area value", 99.9999 == reader->GetDouble (L"Area"));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect vacant value", reader->GetBoolean (L"Vacant"));
                    CPPUNIT_ASSERT_MESSAGE ("incorrect birthday value", 2005 == reader->GetDateTime (L"Birthday").year);
                    CPPUNIT_ASSERT_MESSAGE ("incorrect birthday value", 3 == reader->GetDateTime (L"Birthday").month);
                    CPPUNIT_ASSERT_MESSAGE ("incorrect birthday value", 22 == reader->GetDateTime (L"Birthday").day);
                    CPPUNIT_ASSERT_MESSAGE ("geometry is null", !reader->IsNull (L"Geometry"));
                    FdoPtr<FdoByteArray> before = geometry2->GetGeometry ();
                    FdoPtr<FdoByteArray> after = reader->GetGeometry (L"Geometry");
                    int b = before->GetCount ();
                    int a = after->GetCount ();
                    CPPUNIT_ASSERT_MESSAGE ("incorrect geometry size", b == a);
                    int count = before->GetCount ();
                    FdoPtr<FdoFgfGeometryFactory> gf = FdoFgfGeometryFactory::GetInstance();
                    FdoPtr<FdoIGeometry> pGeomB = gf->CreateGeometryFromFgf(before->GetData(), count);
                    FdoPtr<FdoIGeometry> pGeomA = gf->CreateGeometryFromFgf(after->GetData(), count);
                    CPPUNIT_ASSERT_MESSAGE ("incorrect geometry content", UnitTestUtil::PolygonEqual(pGeomB, pGeomA));
                }
            }
            reader->Close ();
        }
    }
    catch (FdoException* ge) 
    {
        TestCommonFail (ge);
    }
}


void UpdateTests::update_null_data_values ()
{
    try
    {
        create_schema (FdoGeometricType_Point, true, true);

        FdoPtr<FdoIInsert> insert = (FdoIInsert*)mConnection->CreateCommand (FdoCommandType_Insert);
        insert->SetFeatureClassName (L"TheSchema:Test");
        FdoPtr<FdoPropertyValueCollection> values = insert->GetPropertyValues ();
        FdoPtr<FdoValueExpression> expression = (FdoValueExpression*)MapInfoTests::ParseByDataType (L"24", FdoDataType_Decimal);
        FdoPtr<FdoPropertyValue> value = FdoPropertyValue::Create (L"Id", expression);
        values->Add (value);
        expression = (FdoValueExpression*)FdoExpression::Parse (L"'1147 Trafford Drive'");
        value = FdoPropertyValue::Create (L"Street", expression);
        values->Add (value);
        // add NULL geometry value:
        FdoPtr<FdoGeometryValue> geometry = FdoGeometryValue::Create ();
        geometry->SetNullValue ();
        value = FdoPropertyValue::Create (L"Geometry", geometry);
        values->Add (value);
        FdoPtr<FdoIFeatureReader> reader = insert->Execute ();
        FdoInt32 featid;
        featid = -1;
        while (reader->ReadNext ())
        {
            if (-1 != featid)
                CPPUNIT_FAIL ("too many features inserted");
            featid = reader->GetInt32 (L"FeatId");
        }
        reader->Close ();
        if (-1 == featid)
            CPPUNIT_FAIL ("too few features inserted");

        // update it
        FdoPtr<FdoIUpdate> update = (FdoIUpdate*)mConnection->CreateCommand (FdoCommandType_Update);
        update->SetFeatureClassName (L"TheSchema:Test");
        wchar_t filter[1024];
        FdoCommonOSUtil::swprintf (filter, ELEMENTS(filter), L"%ls = %d", L"FeatId", featid);
        update->SetFilter (FdoPtr<FdoFilter>(FdoFilter::Parse (filter)));
        values = update->GetPropertyValues ();
        value = FdoPropertyValue::Create ();
        value->SetName (L"Street");
        //Leave NULL: value->SetValue ( ... );
        values->Add (value);
        value = FdoPropertyValue::Create ();
        value->SetName (L"Id");
        //Leave NULL: value->SetValue ( ... );
        values->Add (value);
        if (1 != update->Execute ())
            CPPUNIT_FAIL ("update execute failed");

        // check by doing a select
        FdoPtr<FdoISelect> select = (FdoISelect*)mConnection->CreateCommand (FdoCommandType_Select);
        select->SetFeatureClassName (L"TheSchema:Test");
        reader = select->Execute ();
        while (reader->ReadNext ())
        {
            CPPUNIT_ASSERT_MESSAGE ("incorrect featid value", featid == reader->GetInt32 (L"FeatId"));
            CPPUNIT_ASSERT_MESSAGE ("incorrect id value", reader->IsNull (L"Id"));
            CPPUNIT_ASSERT_MESSAGE ("incorrect street value", reader->IsNull (L"Street"));
            CPPUNIT_ASSERT_MESSAGE ("incorrect area value", reader->IsNull(L"Area"));
            CPPUNIT_ASSERT_MESSAGE ("incorrect vacant value", reader->IsNull(L"Vacant"));
            CPPUNIT_ASSERT_MESSAGE ("incorrect birthday year value", reader->IsNull (L"Birthday"));
            CPPUNIT_ASSERT_MESSAGE ("incorrect geometry value", reader->IsNull (L"Geometry"));
        }
        reader->Close ();
    }
    catch (FdoException* ge) 
    {
        TestCommonFail (ge);
    }
}



void UpdateTests::update_int32 ()
{
    try
    {
        create_schema (FdoGeometricType_Point, true, true);

        // Insert some values:
        /////////////////////////////////////////////////////////

        for(int i = 0; i < 2; i++)
        {
            FdoPtr<FdoIInsert> insert = (FdoIInsert*)mConnection->CreateCommand (FdoCommandType_Insert);
            insert->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            FdoPtr<FdoPropertyValueCollection> values = insert->GetPropertyValues ();
            FdoPtr<FdoValueExpression> expression = (FdoValueExpression*)MapInfoTests::ParseByDataType (L"24", FdoDataType_Decimal);
            FdoPtr<FdoPropertyValue> value = FdoPropertyValue::Create (L"Id", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"-2147483647");
            value = FdoPropertyValue::Create (L"Age", expression);
            values->Add (value);
            // add NULL geometry value:
            FdoPtr<FdoGeometryValue> geometry = FdoGeometryValue::Create ();
            geometry->SetNullValue ();
            value = FdoPropertyValue::Create (L"Geometry", geometry);
            values->Add (value);
            FdoPtr<FdoIFeatureReader> reader = insert->Execute ();
            FdoInt32 featid;
            featid = -1;
            while (reader->ReadNext ())
            {
                if (-1 != featid)
                    CPPUNIT_FAIL ("too many features inserted");
                featid = reader->GetInt32 (L"FeatId");
            }
            reader->Close ();
            if (-1 == featid)
                CPPUNIT_FAIL ("too few features inserted");

            // Read back the values
            FdoPtr<FdoISelect> select1 = (FdoISelect*)mConnection->CreateCommand (FdoCommandType_Select);
            select1->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            reader = select1->Execute ();
            while (reader->ReadNext ())
            {
                CPPUNIT_ASSERT_MESSAGE ("incorrect featid value", featid == reader->GetInt32 (L"FeatId"));
                CPPUNIT_ASSERT_MESSAGE ("incorrect id value", !reader->IsNull (L"Id"));
                CPPUNIT_ASSERT_MESSAGE ("incorrect age value", !reader->IsNull (L"Age"));
                CPPUNIT_ASSERT_MESSAGE ("incorrect MIN INT value", reader->GetInt32 (L"Age") == -2147483647);
                //CPPUNIT_ASSERT_MESSAGE ("incorrect area value", reader->IsNull(L"Area"));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect vacant value", reader->IsNull(L"Vacant"));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect birthday year value", reader->IsNull (L"Birthday"));
                CPPUNIT_ASSERT_MESSAGE ("incorrect geometry value", reader->IsNull (L"Geometry"));
            }
            reader->Close ();

            // Update some values:
            /////////////////////////////////////////////////////////

            FdoPtr<FdoIUpdate> update = (FdoIUpdate*)mConnection->CreateCommand (FdoCommandType_Update);
            update->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            wchar_t filter[1024];
            FdoCommonOSUtil::swprintf (filter, ELEMENTS(filter), L"%ls = %d", L"FeatId", featid);
            update->SetFilter (FdoPtr<FdoFilter>(FdoFilter::Parse (filter)));
            values = update->GetPropertyValues ();
            value = FdoPropertyValue::Create ();
            value->SetName (L"Age");
            value->SetValue (L"2147483646");
            values->Add (value);
            value = FdoPropertyValue::Create ();
            value->SetName (L"Id");
            //Leave NULL: value->SetValue ( ... );
            values->Add (value);
            if (1 != update->Execute ())
                CPPUNIT_FAIL ("update execute failed");


            // Select back some values
            /////////////////////////////////////////////////////////

            FdoPtr<FdoISelect> select = (FdoISelect*)mConnection->CreateCommand (FdoCommandType_Select);
            select->SetFeatureClassName ((strSchema[i] + L":Test").c_str());
            reader = select->Execute ();
            while (reader->ReadNext ())
            {
                CPPUNIT_ASSERT_MESSAGE ("incorrect featid value", featid == reader->GetInt32 (L"FeatId"));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect id value", reader->IsNull (L"Id"));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect age value", !reader->IsNull (L"Age"));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect area value", reader->IsNull(L"Area"));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect vacant value", reader->IsNull(L"Vacant"));
                //CPPUNIT_ASSERT_MESSAGE ("incorrect birthday year value", reader->IsNull (L"Birthday"));
                CPPUNIT_ASSERT_MESSAGE ("incorrect geometry value", reader->IsNull (L"Geometry"));
            }
            reader->Close ();


            // Select back some values with int32 filter
            /////////////////////////////////////////////////////////

            select->SetFilter(L"Age = 2147483646");
            reader = select->Execute ();
            CPPUNIT_ASSERT_MESSAGE("Int32 Filter failed", reader->ReadNext() );
            reader->Close ();

            select->SetFilter(L"Age = 55");
            reader = select->Execute ();
            CPPUNIT_ASSERT_MESSAGE("Int32 Filter failed", !reader->ReadNext() );
            reader->Close ();
        }
    }
    catch (FdoException* ge) 
    {
        TestCommonFail (ge);
    }
}

